package com.sk.web.aop;

import com.sk.web.WebUtil;
import com.sk.web.exception.AccessException;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.Arrays;


/**
 * 访问切面
 *
 * @author smy
 */
@Aspect
@Component
public class AccessAspect {
    @Resource
    private ApplicationContext applicationContext;
    @Resource
    private AccessLogHandler accessLogHandler;

    public Object getAccessInfo(Class<? extends AuthInterface>[] authTypes, AccessPoint point) {
        for (Class<? extends AuthInterface> authType : authTypes) {
            AuthInterface<?> auth = applicationContext.getBean(authType);
            if (auth != null && auth.check(point.authCode())) {
                return auth.getAccessInfo();
            }
        }
        throw new AccessException(1, "auth_not_logged_in");
    }

    @Around("@within(point) && !@annotation(com.sk.web.aop.AccessPoint)")
    public Object aroundController(ProceedingJoinPoint joinPoint, AccessPoint point) throws Throwable {
        return around(joinPoint, point);
    }

    @Around("@annotation(point)")
    public Object aroundMethod(ProceedingJoinPoint joinPoint, AccessPoint point) throws Throwable {
        return around(joinPoint, point);
    }

    private Object around(ProceedingJoinPoint joinPoint, AccessPoint point) throws Throwable {
        AccessLog event = new AccessLog();
        HttpServletRequest request = WebUtil.getRequest();
        if (request != null) {
            event.setUri(request.getRequestURI());
        }
        String className = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        event.setMethod(className + "." + methodName + "()");
        event.setAccess(getAccessInfo(point.value(), point));
        if (point.args()) {
            event.setArgs(Arrays.toString(joinPoint.getArgs()));
        }
        try {
            Object result = joinPoint.proceed();
            if (point.result()) {
                event.setResult(result);
            }
            return result;
        } catch (Throwable e) {
            event.setErrorType(e.getClass().getSimpleName());
            event.setErrorMsg(e.getMessage());
            throw e;
        } finally {
            accessLogHandler.out(event);
        }
    }


}
